package cascade.model {
	import flash.utils.Dictionary;
	
	import flight.mvc.ValueObject;
	
	import mx.collections.ArrayCollection;
	
	[Bindable]
	[RemoteClass(alias="Page")]
	public class Page extends ValueObject
	{
		/**
		 * All the pages loaded into the system
		 */
		public static var pages:Array = [];
		
		/**
		 * A cache of the children collections of parents. When they are first requested
		 * they will be assembled, and afterwards they will just be handed over.
		 */
		private static var collections:Dictionary = new Dictionary(true);
		
		/**
		 * A cache of the parent of a page. When it is first requested it will be located,
		 * and afterwards it will just be handed over.
		 */
		private static var parents:Dictionary = new Dictionary(true);
		
		
		
		public var id:uint;	
		public var redirect_id:uint;
		public var name:String;
		public var depth:uint;
		public var path:String;
		
		public var parent:Page;
		public var children:ArrayCollection;
		
		public var liveRevision:Revision;
		public var draftRevision:Revision;
		public var revisions:ArrayCollection;
		public var contents:ArrayCollection;
		
		
		public function get relativePath():String {
			return path.replace(/^[^\/]+\/?/, "/");
		}
		
		public function get url():String {
			return "http://" + path + (path == domain ? "/" : "");
		}
		
		public function get domain():String {
			var page:Page = this;
			while (page.parent) page = page.parent;
			return page.name;
		}
		
		
		
		// Static API
		
		public static function getPageById(id:uint):Page {
			var pages:ArrayCollection = Cascade.model.pages;
			for (var i:Number = 0; i < pages.length; i++) {
				var page:Page = pages[i];
				if (page.id == id) return page;
			}
			
			return null;
		}
		
		public static function getPage(path:String):Page {
			if (!path)
				return null;
			
			var pages:Array = path.split("/");
			var children:Object = Cascade.model.siteTree;
			if (!children)
				return null;
			
			for (var i:Number = 0; i < pages.length; i++) {
				if (pages[i] == "" && i == pages.length - 1)
					return page;
				else if (pages[i] == "")
					continue;
				
				var found:Boolean = false;
				for (var j:Number = 0; j < children.length; j++) {
					var page:Page = children[j];
					if (page.name == pages[i]) {
						if (i == (pages.length - 1))
							return page;
						
						if (page.children != null) {
							found = true;
							children = page.children;
							break;
						} else {
							return null;
						}
					}
				}
				if (!found)
					return null;
			}
			
			return null;
		}
		
		
		/**
		 * Provides an ArrayCollection of the children of a page. The results of this method
		 * are cached and the same instance of the ArrayCollection is returned every time for
		 * a Page.
		 */
		public static function getChildren(parent:Page):ArrayCollection
		{
			if (parent == null)
				return null;
			
			if (parent in collections)
				return collections[parent];
			
			// assemble the collection
			var collection:ArrayCollection = new ArrayCollection();
			var pages:Array = Page.pages;
			var start:uint = pages.indexOf(parent);
			var slashPosition:uint = parent.path.length;
			var length:uint = pages.length;
			for (var i:uint = start; i < length; i++)
			{
				var page:Page = pages[i];
				
				// if we are no longer in the parent's descendents
				if (page.path.indexOf(parent.path) != 0)
					break;
				
				// if we are directly under the parent page and not more-so
				if (page.path.indexOf("/", slashPosition + 1) == -1)
				{
					parents[page] = parent;
					collection.addItem(page);
				}
			}
			
			return collection;
		}
		
		
		
		
	}
}